<?php
// @formatter:off
/**
 * @file WCToolsManager.php
 * @author Alejandro Dario Simi
 * @date $Date: 2013-08-20 00:23:06 +0000 (Tue, 20 Aug 2013) $
 *
 * $Id: WCToolsManager.php 102 2013-08-20 00:23:06Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/tags/wcomix-1.0.0.1/includes/WCToolsManager.php $
 */
// @formatter:on

require_once dirname(__FILE__)."/WCTool.php";

/**
 * @class WCToolsManager This class is the central place to run wcomix extra
 * tools.
 */
class WCToolsManager {
	/**
	 * @var WCToolsManager This is the sole instance for this singleton class.
	 */
	protected static $_Instance;
	/**
	 * @var string This variable contains the identifier of an extra tool to
	 * be run.
	 */
	protected $_toolId = false;
	/**
	 * @var boolean This flag indicates if this manager should prompt its help
	 * message instead of running a tool.
	 * Also, if there are no extra tool specified, this class prompts its own
	 * help message.
	 */
	protected $_showHelp = false;
	/**
	 * @var boolean This flag indicates if time statistics must be shown or
	 * not.
	 */
	protected $_showTimers = false;
	/**
	 * Prevent users from clone the singleton's instance.
	 */
	public function __clone() {
		trigger_error(__CLASS__.": Clone is not allowed.", E_USER_ERROR);
	}
	//
	// Public methods.
	/**
	 * This method triggers the execution of all the specified extra tool.
	 *
	 * @param string $spacer Since this method prompts text, this parameter
	 * indicates the left margin to be used.
	 */
	public function run($spacer = "") {
		//
		// Creating a shortcut to timers.
		$timer = WCTimer::Instance();
		//
		// Loading parameters and analyzing them.
		$this->loadParams();
		//
		// Checking if this call was a help request. Also, if there's no
		// extra tool specified, help is shown.
		if($this->_showHelp || !$this->_toolId) {
			//
			// Prompting help messages.
			$this->showHelp();
		} else {
			//
			// Loading global settings.
			// @{
			global $wcToolScripts;
			global $wcOptions;
			// @}
			//
			// Setting a default current status.
			$ok = false;
			//
			// Asking for an suitable log.
			$log = WCLog::Get(WC_LOGNAME_TOOL);
			//
			// Starting log.
			$log->set();
			//
			// Checking tool validity.
			if(!$this->validateTool($this->_toolId)) {
				//
				// Prompting tool error.
				$log->write("{$spacer}".WCColorText::ShellYellow("Warning").": Configuration for ID '{$this->_toolId}' seems to be invalid", WCLogLevel::Warning);
				//
				// If it's possible, its name is prompted.
				if(isset($wcToolScripts[$this->_toolId]["name"])) {
					$log->write(" (name: '{$wcToolScripts[$this->_toolId]["name"]}')\n");
				} else {
					$log->write("\n");
				}
			} elseif(!$wcToolScripts[$this->_toolId]["enabled"]) {
				//
				// At this point, this extra tool is configured to
				// be disabled.
				//
				// Prompting tool error.
				$log->write("{$spacer}".WCColorText::ShellYellow("Warning").": Configuration for ID '{$this->_toolId}' seems to be disabled", WCLogLevel::Warning);
				//
				// If it's possible, its name is prompted.
				if(isset($wcToolScripts[$this->_toolId]["name"])) {
					$log->write(" (name: '{$wcToolScripts[$this->_toolId]["name"]}')\n");
				} else {
					$log->write("\n");
				}
			} else {
				//
				// At this point, tool is okey.
				$ok = true;
			}
			//
			// Checking that it's okey to run this tool.
			if($ok) {
				//
				// Setting a timer ID.
				$timerId = "TOOL";
				//
				// Starting timer for current tool.
				$timer->start($timerId);
				//
				// Checking if it needs to load a file.
				if(isset($wcToolScripts[$this->_toolId]["path"])) {
					//
					// Loading the required file.
					require_once $wcToolScripts[$this->_toolId]["path"];
				}
				//
				// Checking tool main class existence.
				if(!class_exists($wcToolScripts[$this->_toolId]["class"])) {
					$log->write("{$spacer}".WCColorText::ShellRed("Error").": Class '{$wcToolScripts[$this->_toolId]["class"]}' for tool '{$this->_toolId}' does not exists.\n", WCLogLevel::Fatal);
					die ;
				}
				//
				// Prompting what is going to be run.
				$log->write($spacer.WCColorText::ShellGreen($wcToolScripts[$this->_toolId]["name"].":")."\n", WCLogLevel::Info);
				//
				// Cleaning all previously set and analyzed
				// options.
				$wcOptions->clear();
				//
				// Creating an object to manage the operation.
				$tool = new $wcToolScripts[$this->_toolId]["class"]();
				//
				// Actually running the cron operation.
				$tool->run("{$spacer}\t");
				//
				// Freeing memory.
				unset($tool);
				//
				// Saving time statistics.
				$timer->save($timerId, "TOOL", $this->_toolId);
				//
				// Prompting stats.
				if($this->_showTimers) {
					$log->write($spacer.WCColorText::ShellGreen($wcToolScripts[$this->_toolId]["name"].':')." took: {$timer->timer($timerId)} ms\n", WCLogLevel::Info);
				}
			}
		}
	}
	/**
	 * This method prompt the help message.
	 *
	 * @param string $spacer Since this method prompts text, this parameter
	 * indicates the left margin to be used.
	 */
	public function showHelp($spacer = "") {
		//
		// Loading global pointers.
		global $wcToolScripts;
		//
		// Checking if there is a specific extra tool set.
		if($this->_toolId !== false) {
			//
			// Checking if the specific extra tool is a valid one.
			if($this->validateTool($this->_toolId)) {
				//
				// Prompting what is going to be shown.
				echo $spacer.WCColorText::ShellGreen($wcToolScripts[$this->_toolId]["name"].":")."\n";
				//
				// Checking if it needs to load a file.
				if(isset($wcToolScripts[$this->_toolId]["path"])) {
					//
					// Loading the required file.
					require_once $wcToolScripts[$this->_toolId]["path"];
				}
				//
				// Creating an object to manage the extra tool.
				$tool = new $wcToolScripts[$this->_toolId]["class"]();
				//
				// Showing the operation's help message.
				$tool->showHelp("{$spacer}\t");
				//
				// Freeing memory.
				unset($tool);
			} else {
				//
				// If it's not valid, an error message is shown.
				$log->write("".WCColorText::ShellRed("Error").": There is no tool with id '{$this->_toolId}' or maybe it is invalid.\n", WCLogLevel::Error);
			}
		} else {
			//
			// When there is no specific extra tool set, main help
			// message must be shown.
			// @{
			echo "Usage:\n";
			echo "\tphp tool.php [options]\n";

			echo "\nOptions:\n";
			echo "\t-h, --help\n";
			echo "\t\tShows this help text.\n\n";
			echo "\t--timers\n";
			echo "\t\tActivates timers prompts.\n";
			echo "\t-T id, --tool id\n";
			echo "\t\tRuns the specified tool. See 'Available Tools' below.\n";
			// @}
			//
			// Prompting available extra tools.
			// @{
			echo "\nAvailable Tools:\n";
			foreach($wcToolScripts as $id => $tool) {
				if($this->validateTool($id)) {
					echo "\t{$id}:\t{$tool["name"]}";
					echo isset($wcToolScripts[$id]["description"]) ? ": {$wcToolScripts[$id]["description"]}" : "";
					echo !$wcToolScripts[$id]["enabled"] ? " (".WCColorText::ShellYellow("Disabled").")" : "";
					echo ".\n";
				}
			}
			// @}
		}
	}
	//
	// Protected methods.
	/**
	 * This method checks if certain extra tool is set.
	 *
	 * @param string $id Extra tool identifier.
	 * @return boolean Returns true when the extra tool is set.
	 */
	protected function hasTool($id) {
		//
		// Loading the global pointers.
		global $wcToolScripts;
		//
		// Returning whether it is set or not.
		return isset($wcToolScripts[$id]);
	}
	/**
	 * This methods loads parameters and flags sets that may be needed for
	 * execution.
	 */
	public function loadParams() {
		//
		// Loading global pointers.
		global $wcOptions;
		//
		// Setting help option:
		//	-h
		//	--help
		if($wcOptions->addOption("Help")) {
			$wcOptions->addOptionTrigger("Help", "h");
			$wcOptions->addOptionTrigger("Help", "help");
		}
		//
		// Setting option to specify certain cron operation:
		//	-T
		//	--single-tool
		if($wcOptions->addValueOption("Tool")) {
			$wcOptions->addOptionTrigger("Tool", "T");
			$wcOptions->addOptionTrigger("Tool", "tool");
		}
		//
		// Activating timers:
		//	--timers
		if($wcOptions->addOption("Timers")) {
			$wcOptions->addOptionTrigger("Timers", "timers");
		}
		//
		// Triggering the options analysis.
		$wcOptions->check();
		//
		// Checking if an extra tool was specified.
		if($wcOptions->activated("Tool")) {
			//
			// Setting the specified an extra tool.
			$this->_toolId = $wcOptions->value("Tool");
		}
		//
		// Checking if help was requested.
		if($wcOptions->activated("Help")) {
			$this->_showHelp = true;
		}
		//
		// Checking if time statistics has to be shown.
		if($wcOptions->activated("Timers")) {
			$this->_showTimers = true;
		}
	}
	/**
	 * This method forces a user login using the root user id.
	 * This method ignores password authentication.
	 */
	protected function login() {
		//
		// Loading global pointers.
		// @{
		global $wcUser;
		global $wcSession;
		// @}
		//
		// Creating a new user to manage the session.
		$wcUser = new WCUser();
		//
		// Loading root user.
		$wcUser->load(WC_USER_ROOT_ID);
		//
		// Starting session.
		$wcSession->login(WC_USER_ROOT_ID);
	}
	/**
	 * This method logs out the root user.
	 */
	protected function logout() {
		//
		// Loading global pointers.
		// @{
		global $wcUser;
		global $wcSession;
		// @}
		//
		// Clearing the user pointer.
		$wcUser = false;
		//
		// Closing session.
		$wcSession->logout();
	}
	/**
	 * This method checks if certain extra tool exists and it is well
	 * specified.
	 *
	 * @param string $id Extra tool identifier.
	 * @return boolean Returns true when the extra tool is set and valid.
	 */
	protected function validateTool($id) {
		//
		// Loading global pointers.
		global $wcToolScripts;

		return ($this->hasTool($id) && isset($wcToolScripts[$id]["class"]) && isset($wcToolScripts[$id]["enabled"]) && ((isset($wcToolScripts[$id]["path"]) && is_readable($wcToolScripts[$id]["path"])) || !isset($wcToolScripts[$id]["path"])));
	}
	//
	// Public class methods.
	/**
	 * This class-method creates and returns the sole instance for this
	 * singleton class.
	 *
	 * @return WCToolsManager Singleton instance.
	 */
	public static function Instance() {
		//
		// Checking if there's no instance yet.
		if(!isset(self::$_Instance)) {
			$c = __CLASS__;
			//
			// Creating the sole instance.
			self::$_Instance = new $c();
		}
		//
		// Returning the class instance.
		return self::$_Instance;
	}
}
?>